<template>
  <el-card class="mt-20" shadow="hover">
    <el-form
      ref="spuFormRef"
      :model="spuFormData"
      :rules="spuRules"
      label-width="100px"
    >
      <el-form-item label="SPU名称" prop="spuName">
        <el-input v-model="spuFormData.spuName" placeholder="请输入SPU名称" />
      </el-form-item>
      <el-form-item label="品牌" prop="tmId">
        <el-select v-model="spuFormData.tmId" placeholder="请选择">
          <el-option
            v-for="trademark in allTrademarkList"
            :key="trademark.id"
            :label="trademark.tmName"
            :value="trademark.id"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="SPU描述" prop="description">
        <el-input
          v-model="spuFormData.description"
          type="textarea"
          placeholder="请输入SPU描述"
          :rows="3"
        ></el-input>
      </el-form-item>
      <el-form-item label="SPU图片" prop="spuImageList">
        <el-upload
          v-model:file-list="spuFormData.spuImageList"
          :action="`${BASE_URL}/admin/product/upload`"
          list-type="picture-card"
          :on-preview="handlePictureCardPreview"
          :before-upload="beforeAvatarUpload"
          :limit="MAX_UPLOAD_LIMIT"
          :on-exceed="handleUploadExceed"
          accept="image/jpeg,image/png"
          :on-success="handleUploadSuccess"
        >
          <el-icon>
            <Plus />
          </el-icon>

          <template #tip>
            <div class="el-upload__tip">只能上传jpg/png文件，且不超过200kb</div>
          </template>
        </el-upload>

        <el-dialog v-model="dialogVisible" width="30%">
          <img :src="dialogImageUrl" alt="预览图片" class="spu__img" />
        </el-dialog>
      </el-form-item>
      <el-form-item label="销售属性" prop="spuSaleAttrList">
        <el-select
          v-model="selectedSaleAttr"
          :placeholder="selectedSaleAttrPlaceholder"
          class="mr-10"
        >
          <!-- <el-option
            v-for="baseSaleAttr in baseSaleAttrList"
            :key="baseSaleAttr.id"
            :label="baseSaleAttr.name"
            :value="baseSaleAttr.id"
          /> -->
          <!-- 添加属性时，需要id和name -->
          <el-option
            v-for="baseSaleAttr in filteredSaleAttrList"
            :key="baseSaleAttr.id"
            :label="baseSaleAttr.name"
            :value="`${baseSaleAttr.id}:${baseSaleAttr.name}`"
          />
        </el-select>
        <el-button
          type="primary"
          :icon="Plus"
          @click="addSaleAttr"
          :disabled="!selectedSaleAttr"
          >添加销售属性</el-button
        >
        <el-table border class="mt-20" :data="spuFormData.spuSaleAttrList">
          <el-table-column
            type="index"
            label="序号"
            align="center"
            width="60"
          />
          <el-table-column prop="saleAttrName" label="属性名" width="200" />
          <el-table-column label="属性值名称列表">
            <template v-slot="{ row }">
              <el-tag
                type="success"
                closable
                v-for="(spuSaleAttrValue, index) in row.spuSaleAttrValueList"
                :key="spuSaleAttrValue.saleAttrValueName"
                class="mr-10"
                @close="delSpuSaleAttrValue(row.spuSaleAttrValueList, index)"
                >{{ spuSaleAttrValue.saleAttrValueName }}</el-tag
              >
              <el-input
                size="small"
                class="el-input_width"
                v-if="row.isShowEdit"
                ref="inputRef"
                v-model="saleAttrValueName"
                @blur="switchShow(row)"
                @keyup.enter="switchShow(row)"
              ></el-input>
              <el-button
                size="small"
                v-else
                :icon="Plus"
                @click="switchEdit(row)"
              ></el-button>
            </template>
          </el-table-column>
          <el-table-column label="操作" width="100">
            <template v-slot="{ row, $index }">
              <el-popconfirm
                :title="`您确定要删除 ${row.saleAttrName} 销售属性吗?`"
                @confirm="delSaleAttr($index)"
              >
                <template #reference>
                  <el-button
                    type="danger"
                    :icon="Delete"
                    size="small"
                    title="删除"
                  />
                </template>
              </el-popconfirm>
            </template>
          </el-table-column>
        </el-table>
      </el-form-item>

      <el-form-item>
        <el-button type="primary" @click="submitForm"> 保存 </el-button>
        <el-button @click="handleCancel">取消</el-button>
      </el-form-item>
    </el-form>
  </el-card>
</template>

<script lang="ts">
export default {
  name: "AddOrUpdateSpu",
};
</script>

<script lang="ts" setup>
import { nextTick, onMounted, reactive, ref, computed } from "vue";
import { ElMessage } from "element-plus";
import { Plus, Delete } from "@element-plus/icons-vue";
import {
  BaseSaleAttrList,
  SpuFormData,
  SpuSaleAttrItem,
  SpuSaleAttrValueList,
  SpuSaleAttrList,
} from "@/api/product/model/spuModel";
import { TrademarkList } from "@/api/product/model/trademarkModel";
import {
  GetBaseSaleAttrListApi,
  AddOrUpdateSpuApi,
  GetSpuImgListApi,
  GetSpuSaleAttrListApi,
  UpdateSpuApi,
} from "@/api/product/spu";
import { GetAllTrademarkListApi } from "@/api/product/trademark";
import { beforeAvatarUpload } from "@/utils/tools";
import type { UploadProps } from "element-plus";
import { useCategoryStore } from "@/stores/category";
import { useSpuStore } from "@/stores/spu";
// 接收父组件传递的自定义事件
const emit = defineEmits(["setShowSpuList"]);

// 点击取消按钮触发的回调
const handleCancel = () => {
  emit("setShowSpuList", 1);
};

// 定义所有品牌列表数据
const allTrademarkList = ref<TrademarkList>([]);

// 定义基础销售属性数据
const baseSaleAttrList = ref<BaseSaleAttrList>([]);

// 销售属性
const selectedSaleAttr = ref("");

// 组件一渲染就发起请求获取基础销售属性和所有品牌列表数据
onMounted(async () => {
  allTrademarkList.value = await GetAllTrademarkListApi();
  // console.log(allTrademarkList.value);
});

onMounted(async () => {
  baseSaleAttrList.value = await GetBaseSaleAttrListApi();
  // console.log(baseSaleAttrList.value);
});

onMounted(async () => {
  const id = spuStore.spu.id as number;
  if (!id) return;
  // 添加SPU或服务器获取SpuImageList的类型，都是 { imgName, imgUrl } 类型
  const spuImageList = await GetSpuImgListApi(id);

  // 将请求的 { imgName, imgUrl } 类型变成 UploadUserFile[] 类型
  spuFormData.spuImageList = spuImageList.map((img) => {
    return {
      name: img.imgName,
      url: img.imgUrl,
      response: {
        data: img.imgUrl,
      },
    };
  });
});

onMounted(async () => {
  const id = spuStore.spu.id as number;
  if (!id) return;
  spuFormData.spuSaleAttrList = await GetSpuSaleAttrListApi(id);
});

/******************* 上传图片功能 ********************/

const dialogImageUrl = ref("");
const dialogVisible = ref(false);

// 请求前缀
const BASE_URL = import.meta.env.VITE_API_URL;

// 定义公共函数
// // 限制图片大小和类型，图片上传前触发的回调

// // 删除图片功能
// const handleRemove: UploadProps["onRemove"] = (uploadFile, uploadFiles) => {
//   console.log(uploadFile, uploadFiles);
// };

// 预览图片功能
const handlePictureCardPreview: UploadProps["onPreview"] = (uploadFile) => {
  dialogImageUrl.value = uploadFile.url as string;
  dialogVisible.value = true;
};

// 上传图片数量限制
// const handleUploadExceed = () => {
//   ElMessage.error("最多只能上传10张图片！");
// };
const MAX_UPLOAD_LIMIT = 10;
const handleUploadExceed = () => {
  ElMessage.error("最多只能上传10张图片！");
};
const isImgHidden = computed(() => {
  return spuFormData.spuImageList.length < MAX_UPLOAD_LIMIT
    ? "inline-flex"
    : "none";
});

// 图片上传成功，清空表单校验
const handleUploadSuccess = () => {
  spuFormRef.value.clearValidate(["spuImageList"]);
};

const spuStore = useSpuStore();

// 定义表单数据和校验规则
// 用来获取el-form组件实例对象
const spuFormRef = ref();
const spuFormData = reactive<SpuFormData>({
  spuName: spuStore.spu.spuName,
  tmId: spuStore.spu.tmId,
  description: spuStore.spu.description,
  spuImageList: [],
  spuSaleAttrList: [],
});

// spuSaleAttrList自定义校验规则
const spuSaleAttrListValidator = (
  rule: any,
  value: SpuSaleAttrList,
  callback: any
) => {
  /*
    rule 校验规则信息，包含规则名称等内容
    value 校验的数据
    callback 一个函数（必须要调用）
      callback() 表单校验通过
      callback(new Error('错误信息')) 表单校验失败，参数就是失败提示的错误信息
  */

  // 1. 销售属性必须有值
  if (!value.length) {
    callback(new Error("请至少添加一个销售属性"));
    return;
  }

  // 2. 每个销售属性的销售属性值列表至少添加一个销售属性值
  if (value.some((spuSaleAttr) => !spuSaleAttr.spuSaleAttrValueList.length)) {
    callback(new Error(" 每个销售属性请至少添加一个销售属性值"));
    return;
  }

  // 校验通过
  callback();
};

// 表单校验规则
const spuRules = reactive({
  spuName: [
    {
      // 必填项
      required: true,
      // 校验失败，错误信息提示
      message: "请输入SPU名称",
      // 触发表单校验的时机：失去焦点
      trigger: "blur",
    },
  ],
  tmId: [
    {
      required: true,
      message: "请输入SPU品牌",
      trigger: "change",
    },
  ],
  description: [
    {
      required: true,
      message: "请输入SPU描述",
      trigger: "blur",
    },
  ],
  spuImgList: [
    {
      required: true,
      message: "请上传SPU图片",
    },
  ],
  spuSaleAttrList: [
    {
      required: true,
      validator: spuSaleAttrListValidator,
    },
  ],
});

/******************* 添加销售属性功能 ********************/
// 判断基础销售属性是否在销售属性列表数据中
const filteredSaleAttrList = computed(() =>
  baseSaleAttrList.value.filter(
    (baseSaleAttr) =>
      !spuFormData.spuSaleAttrList.some(
        (spuSaleAttr) => spuSaleAttr.baseSaleAttrId === baseSaleAttr.id
      )
  )
);

// 下拉框提示信息
const selectedSaleAttrPlaceholder = computed(() => {
  const length = filteredSaleAttrList.value.length;
  return length ? `剩余${length}个销售属性` : "没有剩余销售属性";
});

// 添加销售属性
const addSaleAttr = () => {
  // 获取销售属性的id和name
  const [id, name] = selectedSaleAttr.value.split(":");
  // 销售属性列表数据添加一条销售属性
  spuFormData.spuSaleAttrList.push({
    // 基础销售属性id
    baseSaleAttrId: +id,
    // 基础销售属性name
    saleAttrName: name,
    // 销售属性值
    spuSaleAttrValueList: [],
    // 编辑和显示销售属性
    isShowEdit: false,
  });

  // 清空下拉框的值
  selectedSaleAttr.value = "";
};

// 点击删除销售属性按钮触发的回调
const delSaleAttr = (index: number) => {
  spuFormData.spuSaleAttrList.splice(index, 1);
};

// 获得输入框ref实例
const inputRef = ref();

// 每一次编辑的标识
const isEditing = ref(false);

// 点击按钮切换编辑模式
const switchEdit = async (row: SpuSaleAttrItem) => {
  // 判断是否有进入编辑模式
  if (isEditing.value) {
    ElMessage.warning("请完成之前的编辑");
    return;
  }
  isEditing.value = true;
  // 显示输入框
  row.isShowEdit = true;
  // 数据更新是异步，页面更新是异步
  await nextTick();
  // 页面一渲染，输入框获得焦点
  inputRef.value.focus();
};

// 收集输入框的数据
const saleAttrValueName = ref("");

// 输入框失去焦点/按下回车键，显示销售属性值
const switchShow = (row: SpuSaleAttrItem) => {
  // 判断当前行销售属性值是否重复
  if (
    row.spuSaleAttrValueList.some(
      (spuSaleAttrValue) =>
        spuSaleAttrValue.saleAttrValueName === saleAttrValueName.value
    )
  ) {
    ElMessage.warning("不能添加相同的属性值");
    return;
  }
  isEditing.value = false;
  row.isShowEdit = false;
  // 判断是否输入值
  if (!saleAttrValueName.value) return;
  // 当前行添加销售数据
  row.spuSaleAttrValueList.push({
    baseSaleAttrId: row.baseSaleAttrId,
    saleAttrValueName: saleAttrValueName.value,
  });
  // 清空输入的值
  saleAttrValueName.value = "";
};

// 点击关闭tag
const delSpuSaleAttrValue = (
  spuSaleAttrValueList: SpuSaleAttrValueList,
  index: number
) => {
  // 删除此销售属性值
  spuSaleAttrValueList.splice(index, 1);
};

const categoryStore = useCategoryStore();

const submitForm = async () => {
  await spuFormRef.value.validate();
  const id = spuStore.spu.id;
  const data = {
    category3Id: categoryStore.category3Id,
    ...spuFormData,
    // 组件表单收集的图片数据为name response.data
    // 发送请求需要的图片数据为 imgName imgUrl
    spuImageList: spuFormData.spuImageList.map((image) => {
      return {
        imgName: image.name,
        imgUrl: (image.response as { data: string }).data,
      };
    }),
  };
  if (id) {
    await UpdateSpuApi({
      ...data,
      id,
    });
  } else {
    await AddOrUpdateSpuApi(data);
  }
  ElMessage.success(`${id ? "更新" : "添加"}SPU成功`);
  handleCancel();
};
</script>

<style scoped>
:deep(.el-upload) {
  display: v-bind(isImgHidden);
}

.el-input_width {
  width: 150px;
}
</style>
